package ca.ericslandry.client.mvp.presenter;

import java.util.HashMap;
import java.util.List;

import net.customware.gwt.dispatch.client.DispatchAsync;
import net.customware.gwt.presenter.client.EventBus;
import net.customware.gwt.presenter.client.place.Place;
import net.customware.gwt.presenter.client.place.PlaceRequest;
import ca.ericslandry.client.GwtCallback;
import ca.ericslandry.client.resource.MyConstants;
import ca.ericslandry.shared.domain.Issue;
import ca.ericslandry.shared.event.IssueSavedEvent;
import ca.ericslandry.shared.event.LogoutEvent;
import ca.ericslandry.shared.rpc.GetIssues;
import ca.ericslandry.shared.rpc.GetIssuesResult;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.logical.shared.HasSelectionHandlers;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.HTMLTable.Cell;
import com.google.inject.Inject;

public class IssueListPresenter extends BasePresenter<IssueListPresenter.Display> {
	public interface Display extends BaseDisplay {
		void addIssueList(List<Issue> issueList, int startRow);

		HasClickHandlers getMore();

		HasSelectionHandlers<Cell> getSelectionSource();

		void reset();

		/**
		 * There are no more issues to fetch
		 */
		void noMoreIssues();

		void noIssues();
	}

	public static final Place PLACE = new Place("issueList");
	private DispatchAsync dispatcher;
	private ContentPresenter contentPresenter;
	private HashMap<Integer, Issue> idMap = new HashMap<Integer, Issue>();
	private static final int ROWS_TO_FETCH = 10;
	private int rowIndex = 0;

	@Inject
	public IssueListPresenter(final Display display, final EventBus eventBus, DispatchAsync dispatcher,
			ContentPresenter contentPresenter, IssuePresenter issuePresenter) {
		super(display, eventBus);
		this.dispatcher = dispatcher;
		this.contentPresenter = contentPresenter;
		bind();
	}

	@Override
	protected void onBind() {
		Log.debug("onBind: issuelist");
		// EVENT: Issue saved
		registerHandler(eventBus.addHandler(IssueSavedEvent.TYPE, new IssueSavedEvent.Handler() {
			@Override
			public void onIssueSaved(IssueSavedEvent event) {
				showIssues();
			}
		}));
		// select issue from list
		/*
		 * registerHandler(display.getSelectionSource().addSelectionHandler(new
		 * SelectionHandler<Cell>() {
		 * 
		 * @Override public void onSelection(SelectionEvent<Cell> event) { Cell
		 * cell = event.getSelectedItem(); Issue issue =
		 * idMap.get(cell.getRowIndex()); issuePresenter.showIssue(issue); //
		 * TODO: Certain columns might trigger different actions (voting // or
		 * something else) } }));
		 */
		// ACTION: show more issues
		registerHandler(display.getMore().addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				showMore();
			}
		}));
		// EVENT: Logout
		registerHandler(eventBus.addHandler(LogoutEvent.TYPE, new LogoutEvent.Handler() {
			@Override
			public void onLogout(LogoutEvent event) {
				showIssues();
			}
		}));
	}

	private void showMore() {
		dispatcher.execute(new GetIssues(rowIndex, ROWS_TO_FETCH), new GwtCallback<GetIssuesResult>(dispatcher,
				eventBus, display) {
			@Override
			public void callback(GetIssuesResult result) {
				List<Issue> issueList = result.getIssueList();
				if (issueList != null) {
					if (issueList.isEmpty()) {
						if (rowIndex == 0) {
							display.noIssues();
						} else {
							display.noMoreIssues();
						}
					} else {
						display.addIssueList(issueList, rowIndex);
						// cache issues to rowIndex
						for (Issue issue : issueList) {
							idMap.put(rowIndex++, issue);
						}
					}
				}
			}
		});
	}

	public void showIssues() {
		display.reset();
		rowIndex = 0;
		idMap.clear();
		contentPresenter.getDisplay().setContent(display.asWidget());
		showMore();
	}

	@Override
	public Place getPlace() {
		return PLACE;
	}

	@Override
	protected void onPlaceRequest(PlaceRequest placeReq) {
		String action = placeReq.getParameter(ACTION, null);
		if (MY.equals(action)) {
			Log.info("onPlaceRequest: show my issues");
		} else {
			// Default action
			Log.info("onPlaceRequest: show latest issues");
			showIssues();
		}
	}

	public static PlaceRequest getDefaultPlaceRequest() {
		return new PlaceRequest(PLACE);
	}

	public static Hyperlink getLinkAllIssues() {
		PlaceRequest placeReq = new PlaceRequest(PLACE);
		return new Hyperlink(MyConstants.INSTANCE.allIssues(), placeReq.toString());
	}

	public static Hyperlink getLinkIssuesByMe() {
		PlaceRequest placeReq = new PlaceRequest(PLACE).with(ACTION, MY);
		return new Hyperlink(MyConstants.INSTANCE.issuesByMe(), placeReq.toString());
	}
}
